package com.swak.fx.support;

import java.util.List;

import com.google.common.primitives.Doubles;
import com.sun.javafx.stage.WindowHelper;
import com.swak.fx.support.animation.AnimateFXInterpolator;
import com.swak.fx.support.ui.UI;
import com.swak.fx.support.ui.UI.Berth;
import com.swak.fx.support.ui.UIEvent;
import com.swak.utils.Lists;

import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.geometry.Bounds;
import javafx.geometry.Rectangle2D;
import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.util.Duration;
import lombok.Getter;
import lombok.Setter;

/**
 * 自定义的窗体:
 * 
 * Platform.setImplicitExit(false); Platform.exit();
 * 
 * @author lifeng
 */
public class Window extends AbstractPage {

	private double offsetX = -1;
	private double offsetY = -1;
	private boolean dragging = false;
	private double lastX = 0.0d;
	private double lastY = 0.0d;
	private double lastWidth = 0.0d;
	private double lastHeight = 0.0d;

	private double ADJUST_SIZE = 5;
	private boolean resizing = false;
	private boolean draggingTop;
	private boolean draggingTopRight;
	private boolean draggingRight;
	private boolean draggingRightBottom;
	private boolean draggingBottom;
	private boolean draggingBottomLeft;
	private boolean draggingLeft;
	private boolean draggingLeftTop;

	private double minWidth;
	private double minHeight;
	private double maxWidth;
	private double maxHeight;

	@Setter
	protected boolean resizeAble = true;
	@Setter
	protected boolean dragAble = true;
	@Setter
	protected boolean berthAble = true;
	@Setter
	protected boolean storePageConfigAble = false;

	@Getter
	protected Stage stage;
	@Getter
	protected Scene scene;

	/**
	 * 窗口状态
	 */
	private int state;

	private final BooleanProperty maximizedProperty = new SimpleBooleanProperty(false);
	private final ObjectProperty<UI.Berth> berthProperty = new SimpleObjectProperty<>(UI.Berth.NONE);
	private final DoubleProperty stagexProperty = new SimpleDoubleProperty();
	private final DoubleProperty stageyProperty = new SimpleDoubleProperty();
	private final ObservableList<javafx.stage.Screen> realScreensProperty = javafx.stage.Screen.getScreens();
	private ReadOnlyObjectProperty<javafx.stage.Screen> realScreenProperty;

	public Window() {
		this.stage = createStage();
	}

	public Window(Stage stage) {
		this.stage = stage;
	}

	public Window(Stage stage, int adjust) {
		this.stage = stage;
		this.ADJUST_SIZE = adjust;
	}

	@Override
	public void initializeParts() {
		super.initializeParts();
		this.minWidth = this.root.getMinWidth();
		this.minHeight = this.root.getMinHeight();
		this.maxWidth = this.root.getMaxWidth();
		this.maxHeight = this.root.getMaxHeight();
		this.scene = new Scene(root, Color.TRANSPARENT);
		this.scene.getStylesheets().add("css/common.css");
		this.stage.setScene(scene);
		this.stage.setTitle(this.fxmlRender.getTitle());
		this.stage.initStyle(this.fxmlRender.getStageStyle());
		this.stage.sizeToScene();
		this.realScreenProperty = WindowHelper.getWindowAccessor().screenProperty(this.stage);
	}

	@Override
	public void setupEventHandlers() {
		super.setupEventHandlers();
		this.moveWindowWhit(this.root);
		this.ctlWindowWhit(this.root);
		this.root.addEventHandler(MouseEvent.MOUSE_ENTERED, (e) -> {
			if (this.berthProperty.get() != Berth.NONE) {
				this.berthEventOut();
			}
		});
		this.root.addEventHandler(MouseEvent.MOUSE_EXITED, (e) -> {
			if (this.berthProperty.get() != Berth.NONE && this.berthAble) {
				this.berthEventIn();
			}
		});
		this.root.addEventHandler(UIEvent.UI, (e) -> {
			if (UI.Events.Window_Close.getBindKey().equals(e.getCmd())) {
				this.close();
			}
		});
	}

	@Override
	public void setupValueChangedListeners() {
		super.setupValueChangedListeners();
		this.stage.maximizedProperty().addListener((e, o, n) -> this.onStateChange(UI.States.Window_Max, n));
		this.maximizedProperty.addListener((e, o, n) -> this.onStateChange(UI.States.Window_Max, n));
		this.stage.iconifiedProperty().addListener((e, o, n) -> this.onStateChange(UI.States.Window_Min, n));
		this.stage.alwaysOnTopProperty().addListener((e, o, n) -> this.onStateChange(UI.States.Window_Fix, n));
		this.stage.showingProperty().addListener((e, o, n) -> this.onStateChange(UI.States.Window_Show, n));
		this.stage.focusedProperty().addListener((e, o, n) -> this.onStateChange(UI.States.Window_Front, n));
		this.stagexProperty.addListener((e, o, n) -> this.stage.setX(n.doubleValue()));
		this.stageyProperty.addListener((e, o, n) -> this.stage.setY(n.doubleValue()));
		this.realScreenProperty.addListener((e, o, n) -> this.onRealScreenChanged(n));
		this.realScreensProperty.addListener(this::onRealScreensChanged);
	}

	private void onStateChange(UI.States state, boolean active) {
		synchronized (this) {
			this.state = active ? (this.state | (state.index)) : this.state & (~state.index);
		}
		this.windowStateChange(this.state);
	}

	@Override
	public void windowStateChange(int state) {
		super.windowStateChange(state);
		if (UI.States.isWindowFront(state) && this.root.isVisible() && this.root.isManaged()) {
			this.windowActivatedChange();
		} else if (this.root.isVisible() && this.root.isManaged()) {
			this.windowDeactivatedChange();
		}
	}

	protected void windowActivatedChange() {
		this.fireActivated();
	}

	protected void windowDeactivatedChange() {
		this.fireDeactivated();
	}

	@Override
	protected void useComputedSize() {
		// TODO 不能设置自适应 -- 这里不能删除
	}

	@Override
	public void initializeFinish() {
		super.initializeFinish();
		this.onRealScreenChanged(this.realScreenProperty.get());
	}

	protected void onRealScreenChanged(javafx.stage.Screen sc) {
		Screen screen = new Screen();
		screen.setKey(sc.hashCode());
		screen.setPrimary(sc == javafx.stage.Screen.getPrimary());
		screen.setBounds(sc.getBounds());
		screen.setVisualBounds(sc.getVisualBounds());
		this.stage.getProperties().put(UI.Conts.CurrentScreen_Key, screen);
		this.onRealScreensChanged(null);
	}

	private void onRealScreensChanged(Change<? extends javafx.stage.Screen> ig) {
		List<Screen> screens = Lists.newArrayList();

		// 计算整个屏幕的大小
		double minx = 0;
		double miny = 0;
		double maxx = 0;
		double maxy = 0;
		for (javafx.stage.Screen sc : javafx.stage.Screen.getScreens()) {
			Screen screen = new Screen();
			screen.setKey(sc.hashCode());
			screen.setPrimary(sc == javafx.stage.Screen.getPrimary());
			screen.setBounds(sc.getBounds());
			screen.setVisualBounds(sc.getVisualBounds());
			screens.add(screen);

			minx = Doubles.min(minx, sc.getBounds().getMinX());
			miny = Doubles.min(miny, sc.getBounds().getMinY());
			maxx = Doubles.max(maxx, sc.getBounds().getMaxX());
			maxy = Doubles.max(maxy, sc.getBounds().getMaxY());
		}
		this.stage.getProperties().put(UI.Conts.CurrentScreens_Key, screens);

		// 记录整个屏幕的大小
		Rectangle2D fullBounds = new Rectangle2D(minx, miny, maxx, maxy);
		this.getScreen().setFullBounds(fullBounds);
	}

	protected void layoutPageInScreen(Screen screen, double width, double height) {
		// 处理一个最大值
		Rectangle2D bounds = screen.getVisualBounds();
		width = Doubles.min(width, bounds.getWidth());
		height = Doubles.min(height, bounds.getHeight());

		// 设置坐标
		this.root.setPrefWidth(width);
		this.root.setPrefHeight(height);
		this.stage.setX(this.getCenterX(bounds));
		this.stage.setY(this.getCenterY(bounds));
	}

	@FXML
	public void doubleClickMaximize(MouseEvent evt) {
		if (evt.getClickCount() != 2) {
			return;
		}
		maximize(evt);
	}

	@FXML
	public void toggleFixWindow(MouseEvent evt) {
		this.stage.setAlwaysOnTop(!this.stage.isAlwaysOnTop());
	}

	@FXML
	public void maximize(MouseEvent evt) {
		javafx.stage.Window w = this.stage;
		double currentX = w.getX();
		double currentY = w.getY();
		double currentWidth = w.getWidth();
		double currentHeight = w.getHeight();

		// 已经最大化
		if (this.maximizedProperty.get()) {
			w.setX(lastX);
			w.setY(lastY);
			w.setWidth(lastWidth);
			w.setHeight(lastHeight);
			maximizedProperty.set(false);
		} else {

			Rectangle2D bounds = this.getScreen().getVisualBounds();

			// 鼠标位置
			boolean draggingTop = this.inAdjustRange(evt.getSceneY(), 0);
			boolean draggingBottom = this.inAdjustRange(evt.getSceneY(), this.stage.getHeight());

			// 处于 top or bottom resize
			if (!(draggingTop || draggingBottom)) {
				w.setX(bounds.getMinX() - ADJUST_SIZE);
				w.setWidth(bounds.getWidth() + ADJUST_SIZE * 2);
			}

			w.setY(bounds.getMinY() - ADJUST_SIZE);
			w.setHeight(bounds.getHeight() + ADJUST_SIZE * 2);

			lastX = currentX; // save old dimensions
			lastY = currentY;
			lastWidth = currentWidth;
			lastHeight = currentHeight;
			maximizedProperty.set(true);
		}
		evt.consume();
	}

	@FXML
	public void minimize(MouseEvent evt) {
		this.stage.setIconified(true);
	}

	// 监听 -- 移动窗口的事件
	protected void moveWindowWhit(Node node) {
		node.addEventHandler(MouseEvent.MOUSE_PRESSED, this::startMoveWindow);
		node.addEventHandler(MouseEvent.MOUSE_MOVED, this::movingWindow);
		node.addEventHandler(MouseEvent.MOUSE_DRAGGED, this::draggedWindow);
		node.addEventHandler(MouseEvent.MOUSE_RELEASED, this::endMoveWindow);
	}

	// 监听 -- 控制窗口的事件(最大化、最小化，关闭，固定)
	protected void ctlWindowWhit(Node node) {
		node.addEventHandler(MouseEvent.MOUSE_CLICKED, (e) -> {
			Node target = (Node) e.getTarget();

			// 固定窗口
			if (target.hasProperties() && target.getProperties().get(UI.Events.Window_Fix.getBindKey()) != null) {
				this.toggleFixWindow(e);
			}

			// 最小化
			if (target.hasProperties() && target.getProperties().get(UI.Events.Window_Min.getBindKey()) != null) {
				this.minimize(e);
			}

			// 最大化
			if (target.hasProperties() && target.getProperties().get(UI.Events.Window_Max.getBindKey()) != null) {
				this.maximize(e);
			}

			// 最大化
			if (target.hasProperties() && target.getProperties().get(UI.Events.Window_Max2.getBindKey()) != null) {
				this.doubleClickMaximize(e);
			}

			// 关闭
			if (target.hasProperties() && target.getProperties().get(UI.Events.Window_Close.getBindKey()) != null) {
				this.close();
			}

			// 让 root 获得焦点
			if (target.hasProperties()
					&& target.getProperties().get(UI.Events.Window_Root_Focused.getBindKey()) != null) {
				this.root.requestFocus();
			}

			// 父节双击
			if (target == this.root) {
				this.doubleClickMaximize(e);
			}
		});
	}

	// onMousePressed
	@FXML
	public void startMoveWindow(MouseEvent evt) {
		evt.consume();
		if (this.maximizedProperty.get()) {
			this.offsetX = 0 - lastWidth / 2;
			this.offsetY = 0 - ADJUST_SIZE * 2;
		} else {
			this.offsetX = this.stage.getX() - evt.getScreenX();
			this.offsetY = this.stage.getY() - evt.getScreenY();
		}
		dragging = true;
	}

	// onMouseMoved
	@FXML
	public void movingWindow(MouseEvent evt) {
		evt.consume();
		double startMoveX = evt.getSceneX();
		double startMoveY = evt.getSceneY();
		javafx.stage.Window w = this.root.getScene().getWindow();
		double stageWidth = w.getWidth();
		double stageHeigth = w.getHeight();

		Cursor cursorType = Cursor.DEFAULT;
		this.draggingTop = this.draggingTopRight = this.draggingRight = this.draggingRightBottom = this.draggingBottom = this.draggingBottomLeft = this.draggingLeft = this.draggingLeftTop = false;
		this.draggingTop = this.inAdjustRange(startMoveY, 0);
		this.draggingRight = this.inAdjustRange(startMoveX, stageWidth);
		this.draggingBottom = this.inAdjustRange(startMoveY, stageHeigth);
		this.draggingLeft = this.inAdjustRange(startMoveX, 0);
		this.draggingTopRight = this.draggingTop && this.draggingRight;
		this.draggingRightBottom = this.draggingRight && this.draggingBottom;
		this.draggingBottomLeft = this.draggingBottom && this.draggingLeft;
		this.draggingLeftTop = this.draggingLeft && this.draggingTop;
		this.resizing = this.draggingTop || this.draggingRight || this.draggingBottom || this.draggingLeft
				|| this.draggingTopRight || this.draggingRightBottom || this.draggingBottomLeft || this.draggingLeftTop;

		if (this.draggingTopRight) {
			cursorType = Cursor.NE_RESIZE;
		} else if (this.draggingRightBottom) {
			cursorType = Cursor.SE_RESIZE;
		} else if (this.draggingBottomLeft) {
			cursorType = Cursor.SW_RESIZE;
		} else if (this.draggingLeftTop) {
			cursorType = Cursor.NW_RESIZE;
		} else if (this.draggingTop) {
			cursorType = Cursor.N_RESIZE;
		} else if (this.draggingRight) {
			cursorType = Cursor.E_RESIZE;
		} else if (this.draggingBottom) {
			cursorType = Cursor.S_RESIZE;
		} else if (this.draggingLeft) {
			cursorType = Cursor.W_RESIZE;
		}
		this.root.getScene().setCursor(cursorType);
	}

	private boolean inAdjustRange(double src, double dest) {
		return Math.abs(dest - src) <= ADJUST_SIZE;
	}

	// onMouseDragged
	@FXML
	public void draggedWindow(MouseEvent evt) {
		evt.consume();
		if (!dragging) {
			return;
		}

		if (evt.getSource() == this.root) {
			if (this.resizing) {
				this.draggedWindowOnResize(evt);
				return;
			}

			// 监听全局的事件
			Node node = (Node) evt.getTarget();
			if (node.hasProperties() && node.getProperties().get(UI.Events.Window_Drag.getBindKey()) != null) {
				this.draggedWindowOnMove(evt);
			}
			return;
		}

		if (this.resizing) {
			this.draggedWindowOnResize(evt);
		} else {
			this.draggedWindowOnMove(evt);
		}
	}

	protected void draggedWindowOnMove(MouseEvent evt) {

		// 不能移动
		if (!this.dragAble) {
			return;
		}

		// 恢复常态
		if (this.maximizedProperty.get()) {
			this.maximize(evt);
		}

		// 移动
		double endMoveX = evt.getScreenX();
		double endMoveY = evt.getScreenY();
		this.stage.setX(endMoveX + offsetX);
		this.stage.setY(endMoveY + offsetY);

		// 计算停靠的边界
		// TODO 应该考虑整个屏幕的大小
		Bounds bounds = this.root.localToScreen(this.root.getBoundsInLocal());
		double centerX = bounds.getCenterX();
		double centerY = bounds.getCenterY();
		Rectangle2D screenBounds = this.getScreen().getFullBounds();
		Berth berth = Berth.NONE;
		if (centerX < screenBounds.getMinX()) {
			berth = Berth.LEFT;
		} else if (centerX > screenBounds.getMaxX()) {
			berth = Berth.RIGHT;
		} else if (centerY < 0) {
			berth = Berth.TOP;
		}
		this.berthProperty.set(berth);
	}

	private boolean canResizeWidth(double width) {
		return (this.minWidth <= width || this.minWidth < 0) && (width <= this.maxWidth || this.maxWidth < 0);
	}

	private boolean canResizeHeight(double height) {
		return (this.minHeight <= height || this.minHeight < 0) && (height <= this.maxHeight || this.maxHeight < 0);
	}

	protected void draggedWindowOnResize(MouseEvent evt) {
		if (!this.resizing || !this.resizeAble) {
			return;
		}

		if (this.draggingRight) {
			double endMoveX = evt.getSceneX();
			if (canResizeWidth(endMoveX)) {
				this.root.setPrefWidth(endMoveX);
				this.stage.setWidth(endMoveX);
			}
		}
		if (this.draggingBottom) {
			double endMoveY = evt.getSceneY();
			if (canResizeHeight(endMoveY)) {
				this.root.setPrefHeight(endMoveY);
				this.stage.setHeight(endMoveY);
			}
		}
		if (this.draggingLeft) {
			javafx.stage.Window w = this.stage;
			double stageWidth = w.getWidth();
			double stageX = w.getX();
			double endMoveX = evt.getScreenX();

			double distance = stageX - endMoveX;
			double endWidth = stageWidth + distance;
			if (canResizeWidth(endWidth)) {
				this.root.setPrefWidth(endWidth);
				this.stage.setWidth(endWidth);
				this.stage.setX(endMoveX);
			}
		}
		if (this.draggingTop) {
			javafx.stage.Window w = this.stage;
			double stageHeight = w.getHeight();
			double stageY = w.getY();
			double endMoveY = evt.getScreenY();

			double distance = stageY - endMoveY;
			double endHeight = stageHeight + distance;
			if (canResizeHeight(endHeight)) {
				this.root.setPrefHeight(endHeight);
				this.stage.setHeight(endHeight);
				this.stage.setY(endMoveY);
			}
		}
	}

	// onMouseReleased
	@FXML
	public void endMoveWindow(MouseEvent evt) {
		evt.consume();
		this.offsetX = 0;
		this.offsetY = 0;
		this.dragging = false;
		this.resizing = false;
		this.draggingTop = this.draggingTopRight = this.draggingRight = this.draggingRightBottom = this.draggingBottom = this.draggingBottomLeft = this.draggingLeft = this.draggingLeftTop = false;
		this.root.getScene().setCursor(Cursor.DEFAULT);
	}

	protected void berthEventIn() {
		Rectangle2D screenBounds = this.getScreen().getVisualBounds();
		double changex = 0;
		double changey = 0;
		Berth berth = this.berthProperty.get();
		if (berth == Berth.LEFT) {
			changey = this.getCenterY(screenBounds);
			changex = screenBounds.getMinX() - this.stage.getWidth() + ADJUST_SIZE;
		} else if (berth == Berth.RIGHT) {
			changey = this.getCenterY(screenBounds);
			changex = screenBounds.getMaxX() - ADJUST_SIZE;
		} else if (berth == Berth.TOP) {
			changex = this.getCenterX(screenBounds);
			changey = screenBounds.getMinY() - this.stage.getHeight() + ADJUST_SIZE;
		}
		{
			Timeline berthEventIn = new Timeline(
					new KeyFrame(Duration.millis(0),
							new KeyValue(stagexProperty, this.stage.getX(), AnimateFXInterpolator.EASE)),
					new KeyFrame(Duration.millis(1000),
							new KeyValue(stagexProperty, changex, AnimateFXInterpolator.EASE)));
			berthEventIn.play();
		}
		{
			Timeline berthEventIn = new Timeline(
					new KeyFrame(Duration.millis(0),
							new KeyValue(stageyProperty, this.stage.getY(), AnimateFXInterpolator.EASE)),
					new KeyFrame(Duration.millis(1000),
							new KeyValue(stageyProperty, changey, AnimateFXInterpolator.EASE)));
			berthEventIn.play();
		}
	}

	protected void berthEventOut() {
		Rectangle2D screenBounds = this.getScreen().getVisualBounds();
		double change = 0;
		Berth berth = this.berthProperty.get();
		if (berth == Berth.LEFT) {
			change = screenBounds.getMinX() - ADJUST_SIZE;
		} else if (berth == Berth.RIGHT) {
			change = screenBounds.getMaxX() - this.root.prefWidth(-1) + ADJUST_SIZE;
		} else if (berth == Berth.TOP) {
			change = screenBounds.getMinY() - ADJUST_SIZE;
		}
		if (berth == Berth.LEFT || berth == Berth.RIGHT) {
			Timeline berthEventIn = new Timeline(
					new KeyFrame(Duration.millis(0),
							new KeyValue(stagexProperty, this.stage.getX(), AnimateFXInterpolator.EASE)),
					new KeyFrame(Duration.millis(1000),
							new KeyValue(stagexProperty, change, AnimateFXInterpolator.EASE)));
			berthEventIn.play();
		} else if (berth == Berth.TOP) {
			Timeline berthEventIn = new Timeline(
					new KeyFrame(Duration.millis(0),
							new KeyValue(stageyProperty, this.stage.getY(), AnimateFXInterpolator.EASE)),
					new KeyFrame(Duration.millis(1000),
							new KeyValue(stageyProperty, change, AnimateFXInterpolator.EASE)));
			berthEventIn.play();
		}
	}

	protected double getCenterX(Rectangle2D screenBounds) {
		// Rectangle2D screenBounds = this.getScreen().getVisualBounds();
		double width = this.getWidth();
		return screenBounds.getMinX() + (screenBounds.getWidth() - width) * 0.5;
	}

	protected double getCenterY(Rectangle2D screenBounds) {
		// Rectangle2D screenBounds = this.getScreen().getVisualBounds();
		double height = this.getHeight();
		return screenBounds.getMinY() + (screenBounds.getHeight() - height) * 0.5;
	}

	protected double getWidth() {
		double width = this.stage.getWidth();
		if (width <= 0 || Double.isNaN(width)) {
			width = this.root.getWidth();
		}
		if (width <= 0 || Double.isNaN(width)) {
			width = this.root.prefWidth(-1);
		}
		return width;
	}

	protected double getHeight() {
		double height = this.stage.getHeight();
		if (height <= 0 || Double.isNaN(height)) {
			height = this.root.getHeight();
		}
		if (height <= 0 || Double.isNaN(height)) {
			height = this.root.prefHeight(-1);
		}
		return height;
	}

	public void show() {
		this.stage.show();
		this.stage.toFront();
		if (this.stage.isIconified()) {
			this.stage.setIconified(false);
		}
	}

	/**
	 * 这个关闭不会调用： beforeClose
	 */
	protected void forceClose() {
		if (this.stage != null) {
			this.stage.close();
		}
	}

	/**
	 * 开启了： Platform.setImplicitExit(false); close 和 hide 是一样的， 真正的退出需要执行
	 * 
	 * Platform.exit();
	 */
	public void close() {
		if (!this.beforeClose()) {
			return;
		}
		if (this.stage != null) {
			this.stage.close();
		}
	}

	/**
	 * 拦截关闭窗体 true：窗体可关闭 false：窗体不可关闭
	 * 
	 * @return
	 */
	protected boolean beforeClose() {
		return true;
	}

	@Override
	public void destory() {
		super.destory();

		try {
			this.storePageConfig();
		} catch (Exception e) {
		}

		if (this.stage != null) {
			this.stage.close();
			this.stage.setScene(null);
		}
	}

	protected void storePageConfig() {
		if (!this.storePageConfigAble) {
			return;
		}
		this.setPageConfig(UI.Conts.Settings_Page_Screen, String.valueOf(this.getScreen().getKey()));
		this.setPageConfig(UI.Conts.Settings_Page_Width, String.valueOf(this.stage.widthProperty().doubleValue()));
		this.setPageConfig(UI.Conts.Settings_Page_Height, String.valueOf(this.stage.heightProperty().doubleValue()));
		this.setPageConfig(UI.Conts.Settings_Page_X, String.valueOf(this.stage.xProperty().doubleValue()));
		this.setPageConfig(UI.Conts.Settings_Page_Y, String.valueOf(this.stage.yProperty().doubleValue()));
	}

	protected static Stage createStage() {
		return createStage(true);
	}

	protected static Stage createStage(boolean modal) {
		Stage newStage = new Stage(StageStyle.TRANSPARENT);
		// 是否是模态窗口
		if (modal) {
			newStage.initOwner(Display.getStage());
			newStage.initModality(Modality.WINDOW_MODAL);
		}
		newStage.setTitle(Display.getStage().getTitle());
		newStage.getIcons().addAll(Display.getStage().getIcons());
		return newStage;
	}

	@SuppressWarnings("unchecked")
	public static <T extends Window> T New(Class<T> theClass) {
		return (T) AbstractApplication.INSTANCE.NewWindow(theClass);
	}

	@SuppressWarnings("unchecked")
	public static <T extends Window> T New(Class<T> theClass, Stage stage) {
		return (T) AbstractApplication.INSTANCE.NewWindow(theClass, stage);
	}
}
